home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / LIBRARY / PAS_0793 / MULTKEYS.TXT < prev    next >
Text File  |  1993-08-01  |  7KB  |  177 lines

  1. ─ Fido Pascal Conference ────────────────────────────────────────────── PASCAL ─
  2. Msg  : 226 of 249                                                               
  3. From : Lou Duchez                          1:157/200.0          27 Jul 93  08:22 
  4. To   : Salim Samaha                                                              
  5. Subj : 1/2 multiple keys                                                      
  6. ────────────────────────────────────────────────────────────────────────────────
  7. HOW TO ENABLE YOUR KEYBOARD TO READ MULTIPLE KEYS SIMULTANEOUSLY
  8.  
  9. -Page 1 of 2
  10.  
  11. - by Lou DuChez
  12.  
  13. Manuals will tell you that you can read port 60h to determine if a
  14. key is being pressed/released.  What they don't tell you is, the
  15. keyboard interrupt (09h) will instantly process the port and reset
  16. it to zero as soon as any keyboard activity occurs; so by the time you
  17. get to look at it, port 60h invariably contains no data for you to use.
  18. To use port 60h, then, you'll need to alter the keyboard interrupt so
  19. that the port's data gets stored to variables you can use.
  20.  
  21. The routine in this post will let you read multiple keys simultaneously.
  22. I will do this by making an array [0..127] of boolean called KeyDown:
  23. it records the status of each key on your keyboard with "true" meaning
  24. "down."  The lower seven bits of port 60h tell you which key is being
  25. reported on (i.e., the "scan code" of the key); the high bit indicates a
  26. "press" if it's 0 and a "release" it it's 1.  So when you press or
  27. release a key, my new keyboard interrupt routine will determine which key
  28. is being altered, and set the proper element of KeyDown to the right value.
  29.  
  30. You will probably want to compile your program as "far" ({$F+}), or make
  31. a unit out of these routines.  You will need these global variable
  32. declarations:
  33. ______
  34.  
  35. var keydown: array[0..127] of boolean;   { see the above }
  36.     oldkbdint: pointer;         { points to the "normal" keyboard handler }
  37. ______
  38.  
  39. Next, put these lines of code in your program, maybe in the "main" part:
  40. ______
  41.  
  42. getintvec($09, oldkbdint);        { record location of old keyboard int }
  43. setintvec($09, addr(newkbdint));  { this line installs the new interrupt }
  44. ______
  45.  
  46. We need to recall the location of the "normal" keyboard handler for two
  47. reasons: because we'll need to restore it when the program terminates, and
  48. because the "new" handler will need to call it.  (The "old" handler performs
  49. certain housekeeping duties that we still need.)  This is the new keyboard
  50. interrupt handler:
  51. ______
  52.  
  53. procedure newkbdint; interrupt;
  54. begin
  55.   keydown[port[$60] mod 128] := (port[$60] < 128);  { record current status }
  56.   runproc(oldkbdint);                                 { call old interrupt }
  57.   asm cli; end;                               { disable hardware interrupts }
  58.   memw[$0040:$001a] := memw[$0040:$001c];     { clear the keyboard buffer }
  59.   asm sti; end;                               { enable hardware interrupts }
  60.   end;
  61. ______
  62.  
  63. Explanations:
  64.  
  65. The "KeyDown" line checks the indicated key for a press or release.  If
  66. the port is returning something less than 128 (i.e., high bit of "0"), the
  67. key is not down.  The next line, the RunProc line, calls the "normal"
  68. interrupt.  RunProc is a procedure that looks like this:
  69. ______
  70.  
  71. procedure runproc(proctorun: pointer);
  72. begin
  73.   inline($9c/           { PUSHF }
  74.          $ff/$5e/$06)   { CALL DWORD PTR [BP+6] }
  75.   end;
  76. ______
  77.  
  78. (A footnote: this procedure was provided by Stephen O'Brien in his "Turbo
  79. Pascal 6.0: The Complete Reference.")  The "ASM CLI; END" line performs
  80. an assembler instruction to prevent hardware interrupts just long enough
  81. for the next line to clear the keyboard buffer; then the "ASM STI; END"
  82. line re-enables hardware interrupts.  (About the keyboard buffer: it's a
  83. ring buffer, where a block of usually 32 bytes is used to store unprocessed
  84. keystrokes.  It's a "ring" because there are pointers to the "first unread"
  85. character and the "last unread" character.  The "Memw" line sets the
  86. pointers equal to each other, thus "clearing" the buffer.)
  87.  
  88. Finally, when you're done with your new keyboard interrupt, restore the
  89. "normal" keyboard handler with this line:
  90.  
  91. setintvec($09, oldkbdint);
  92.  
  93. And that should do it.
  94.  
  95. -Page 2 of 2
  96.  
  97. From the top, your program should look like:
  98. ______
  99.  
  100. {$F+}
  101. Program KeyboardThingie;
  102. Uses Dos;                 { needed for all the interrupt stuff }
  103.  
  104. var keydown: array[0..127] of boolean;
  105.     oldkbdint: pointer;
  106.  
  107. procedure runproc();
  108.   .
  109.   .  { full "runproc" code here }
  110.   .
  111.  
  112. procedure newkbdint; interrupt;
  113.   .
  114.   .  { full keyboard interrupt code here }
  115.   .
  116.  
  117. begin { your main program? maybe, or maybe not }
  118.   for counter := 0 to 127 do keydown[counter] := false; { clears array }
  119.   getintvec($09, oldkbdint);
  120.   setintvec($09, addr(newkbdint));
  121.     .
  122.     . { put in code here that actually does something }
  123.     .
  124.   setintvec($09, oldkbdint);
  125.   end;
  126. ______
  127.  
  128. Something to watch out for: this routine does nothing about "Ctrl-Break."
  129. If someone hits "Ctrl-Break" while the alternate keyboard handler is
  130. working, the program will terminate.  Which means that the block of memory
  131. holding the "new" handler will be open to reuse by other programs.  Which
  132. means that your system will crash.  So to prevent this, you should also
  133. make a new "Ctrl-Break" handler.  The approach is much like the above,
  134. but with two differences: the "Ctrl-Break" interrupt is interrupt 1Bh,
  135. and you'll want your new handler to do absolutely nothing.  NOTHING.
  136. As in, no lines of code between "begin" and "end."
  137.  
  138. Finally, to use all this, you'll need to know the "scan codes".  Notice
  139. that a typical key can generate two different characters (like "1" and
  140. "!"); the two characters have the same scan code because the same key
  141. produces both.  Here are the scan codes:
  142. ______
  143.  
  144. "1" - "=" : $02 - $0D
  145. "Q" - "}" : $10 - $1B
  146. "A" - '"' (the "quote" key) : $1E - $28
  147. "Z" - "?" : $29 - $35
  148. F1 - F10  : $3B - $44
  149.  
  150. "space" :      $39    "~" :         $29     "|" :           $2b
  151. "escape" :     $01    "backspace" : $0E     "control" :     $1D
  152. "left shift" : $2A    "caps lock" : $3A     "scroll lock" : $46
  153. "tab" :        $0F    "enter" :     $1C     "right shift" : $36
  154. "printscreen": $37    "alt" :       $38     "home" :        $47
  155. "up" :         $48    "page up" :   $49     "minus" (pad) : $4A
  156. "left arrow" : $4B    "middle" key: $4C     "rightarrow":   $4D
  157. "plus" (pad) : $4E    "end":        $4F     "down":         $50
  158. "page down" :  $51    "insert" :    $52     "delete" :      $53
  159. "num lock" :   $45    F11 :         $D9     F12 :           $DA
  160. ______
  161.  
  162. Use them however you want.  I tend to set up the non-character codes
  163. (like the arrows and "enter" key) as constants.  For the "character"
  164. codes (like '1' and 'K'), I set up an array called ScanOf: it's an
  165. array[' '..'~'] of byte that I use to get the scan codes of characters
  166. with.  For example, at the start of my unit that contains all this, I
  167. load in ScanOf['3'] with $04, meaning that character '3' corresponds
  168. to scan code $04.  Then, if I need to see if the '3' key is down,
  169. I check:
  170.  
  171. KeyDown[ScanOf['3']]
  172. ^^^^^^^ ^^^^^
  173.    |    converts character to scan code (i.e., which "key")
  174.    +--- checks the specified key
  175.  
  176. "True" means "it's down."  But do what you want.
  177. ______